#ifndef MODBUS_RTU_H
#define MODBUS_RTU_H

#include <stdbool.h>

// -------------------------- Modbus RTU Protocol Constants --------------------------
#define MODBUS_MAX_FRAME_LENGTH    256     // Maximum frame length in bytes
#define MODBUS_BROADCAST_ADDR      0x00    // Broadcast address (all devices)
#define MODBUS_CRC_LENGTH          2       // Length of CRC checksum in bytes
#define MODBUS_MIN_FRAME_LENGTH    4       // Minimum frame length (address + function + CRC)

// -------------------------- Modbus Function Codes --------------------------
typedef enum {
    MODBUS_FUNC_READ_COILS        = 0x01,  // Read coil status
    MODBUS_FUNC_READ_DISCRETE     = 0x02,  // Read discrete inputs
    MODBUS_FUNC_READ_HOLDING      = 0x03,  // Read holding registers
    MODBUS_FUNC_READ_INPUT        = 0x04,  // Read input registers
    MODBUS_FUNC_WRITE_COIL        = 0x05,  // Write single coil
    MODBUS_FUNC_WRITE_REGISTER    = 0x06,  // Write single register
    MODBUS_FUNC_WRITE_MULTIPLE_COILS = 0x0F, // Write multiple coils
    MODBUS_FUNC_WRITE_MULTIPLE_REGISTERS = 0x10 // Write multiple registers
} ModbusFunctionCode;

// -------------------------- Modbus Exception Codes --------------------------
typedef enum {
    MODBUS_EXCEPTION_NONE         = 0x00,  // No exception
    MODBUS_EXCEPTION_ILLEGAL_FUNC = 0x01,  // Illegal function
    MODBUS_EXCEPTION_ILLEGAL_ADDR = 0x02,  // Illegal data address
    MODBUS_EXCEPTION_ILLEGAL_DATA = 0x03,  // Illegal data value
    MODBUS_EXCEPTION_SLAVE_BUSY   = 0x04,  // Slave device busy
    MODBUS_EXCEPTION_ACK          = 0x05,  // Acknowledge
    MODBUS_EXCEPTION_SLAVE_ERROR  = 0x06,  // Slave device error
    MODBUS_EXCEPTION_MEM_PARITY   = 0x08   // Memory parity error
} ModbusExceptionCode;

// -------------------------- Data Structure Definitions --------------------------
/**
 * @brief Modbus RTU frame structure
 * Represents a complete Modbus RTU message frame
 */
typedef struct {
    uint8_t address;                   // Slave device address
    ModbusFunctionCode function;       // Function code
    uint8_t data[MODBUS_MAX_FRAME_LENGTH - 3];  // Data segment (excluding address, function, and CRC)
    uint16_t data_length;              // Length of data segment in bytes
    uint16_t crc;                      // CRC16 checksum value
} ModbusFrame;

/**
 * @brief Modbus receive state machine
 * Tracks the state of incoming data reception
 */
typedef struct {
    uint8_t buffer[MODBUS_MAX_FRAME_LENGTH];  // Buffer for received data
    uint16_t length;                        // Current length of received data
    uint16_t timeout_counter;               // Counter for frame timeout detection
    bool frame_complete;                    // Flag indicating complete frame received
    bool overflow;                          // Flag indicating buffer overflow
} ModbusRxState;

/**
 * @brief Modbus context structure
 * Contains all state information for Modbus communication
 */
typedef struct {
    uint8_t slave_address;                 // Local device address
    ModbusRxState rx_state;                // Receive state information
    uint32_t tick_interval_ms;             // System tick interval in milliseconds
    uint32_t frame_timeout_ms;             // Frame timeout period in milliseconds
} ModbusContext;

// -------------------------- Callback Function Type Definitions --------------------------
/**
 * @brief Data transmission callback function (implemented by hardware layer)
 * @param data Pointer to data to be transmitted
 * @param length Length of data in bytes
 */
typedef void (*ModbusSendCallback)(const uint8_t* data, uint16_t length);

/**
 * @brief Coil read/write callback (implemented by application layer)
 * @param address Coil address
 * @param value Pointer to value (true=1, false=0)
 * @param is_write True for write operation, false for read
 * @return Operation result (true=success)
 */
typedef bool (*ModbusCoilCallback)(uint16_t address, bool* value, bool is_write);

/**
 * @brief Register read/write callback (implemented by application layer)
 * @param address Register address
 * @param value Pointer to register value
 * @param is_write True for write operation, false for read
 * @return Operation result (true=success)
 */
typedef bool (*ModbusRegisterCallback)(uint16_t address, uint16_t* value, bool is_write);

/**
 * @brief Modbus callback interface collection
 * Groups all callback functions for hardware and application interaction
 */
typedef struct {
    ModbusSendCallback send;              // Transmission callback
    ModbusCoilCallback coil_handler;      // Coil handling callback
    ModbusRegisterCallback register_handler; // Register handling callback
} ModbusCallbacks;

// -------------------------- Public Interface Functions --------------------------
/**
 * @brief Initialize Modbus context
 * @param ctx Modbus context pointer
 * @param slave_addr Local device address
 * @param tick_interval System tick interval in milliseconds
 * @param timeout Frame timeout period in milliseconds
 */
void modbus_init(ModbusContext* ctx, uint8_t slave_addr, uint32_t tick_interval, uint32_t timeout);

/**
 * @brief Process received byte (called by hardware layer)     
 * @param ctx Modbus context pointer
 * @param data Received byte
 */
void modbus_receive_byte(ModbusContext* ctx, uint8_t data);

/**
 * @brief System tick handler (called periodically to check timeouts)
 * @param ctx Modbus context pointer
 */
void modbus_tick(ModbusContext* ctx);

/**
 * @brief Process complete frame (called by application layer)
 * @param ctx Modbus context pointer
 * @param callbacks Pointer to callback interface structure
 */
void modbus_process_frame(ModbusContext* ctx, const ModbusCallbacks* callbacks);

/**
 * @brief Send Modbus request (master mode)
 * @param ctx Modbus context pointer
 * @param callbacks Pointer to callback interface structure
 * @param addr Target device address
 * @param func Function code
 * @param data Pointer to data
 * @param data_len Length of data in bytes
 */
void modbus_send_request(ModbusContext* ctx, const ModbusCallbacks* callbacks,
                        uint8_t addr, ModbusFunctionCode func, const uint8_t* data, uint16_t data_len);

#endif // MODBUS_RTU_H
    